package org.zn.note.mybatis;

import org.apache.ibatis.binding.MapperProxy;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.zn.note.mybatis.domain.CmMerchant;
import org.zn.note.mybatis.mapper.CmMerchantMapper;
import org.zn.note.mybatis.setting.MyCache;
import org.zn.note.mybatis.setting.MyObjectFactory;
import org.zn.note.mybatis.setting.MyPlugin;
import org.zn.note.mybatis.util.MyBatisUtils;

import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

/**
 * SqlSessionFactoryBuilder\SqlSessionFactory\SqlSession\Mapper，只有SqlSession需要Close！
 * <p>
 * {@link SqlSessionFactoryBuilder} 方法作用域。用来根据配置(XML or 代码)生成SqlSessionFactory。
 * 方法：只有build()，不过有多种重载(Overload)形式，不同的入参，支持多种方式传入配置信息。
 * 无论以哪种方式传入配置，最终构建为 {@link Configuration}
 * <p>
 * {@link SqlSessionFactory} 全局作用域。应用运行期用同一个，不要重复创建，建议单例，建议一个数据库一个实例。
 * 方法：N种重载的openSession(...)、还有1个{@link SqlSessionFactory#getConfiguration()}
 * 有两个实现类：DefaultSqlSessionFactory(默认的)、SqlSessionManager(目前没用)
 * <p>
 * {@link SqlSession} 请求作用域或方法作用域。非线程安全。一次请求用一个、一个线程用一个，用完要 close。
 * 类似于一个connection，控制事务，要及时关闭，占数据库连接。
 * 老的方式：直接发送SQL，并获取结果。
 * 新的方式：获取Mapper(映射器)，用Mapper发送SQL并获取结果。
 * <p>
 * SQL Mapper，是MyBatis新设计的组件。构成：1个Java接口+1个XML配置(或注解)。发送SQL，返回结果。
 * 映射器实例，方法作用域。从SqlSession中获取。在方法中，随用随取。不用关闭。
 * 生命周期在SqlSession以内，建议控制在一个事务以内。
 * <p>
 * 通过XML配置：{@link MyBatisUtils#createSqlSessionFactoryByXml}，配置文件 mybatis-config.xml
 * 通过JAVA配置：{@link MyBatisUtils#createSqlSessionFactoryByJava}
 * XML方便灵活一些，但是Java配置可以实现更复杂的功能，比如数据库密码加密解密等。
 * <p>
 * 关于MyBatis的Xml配置 (参见mybatis-config.xml)
 * MyBatis缓存 {@link MyCache}
 * MyBatis工厂 {@link MyObjectFactory}
 * MyBatis插件 {@link MyPlugin}
 */

/**
 * 关于MyBatis运行原理
 * MyBatis分为两大部分：
 * 1、配置文件缓存到{@link Configuration}，用以创建{@link SqlSessionFactory}
 * 2、{@link SqlSession} 运行过程
 * Mapper是怎样运行的？ --- 动态代理  参见{@link org.zn.note.mybatis.core.MapperCore}
 */

/**
 * 关于事务 {@link Transaction}
 */

/**
 * MyBatis 运行过程
 * 1、SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream)
 * {@link SqlSessionFactoryBuilder#build(InputStream)} --> {@link SqlSessionFactoryBuilder#build(InputStream, String, Properties)}
 */
public class MybatisApplication {

    public static void main(String[] args) {
        // SqlSession 建议 请求作用域或方法作用域，用后要close，线程不安全
        try (SqlSession session = MyBatisUtils.openSession()) { // AutoCloseable自动关闭
            // 旧的方式：直接用SqlSession发送SQL
//            CmMerchant cmMerchant1 = session.selectOne("org.zn.note.mybatis.mapper.CmMerchantMapper.selectByPrimaryKey", 1);
//            System.out.printf("merchant1:\n%s\n", cmMerchant1);
            // 新的方式：通过SqlSession获取Mapper，然后用Mapper发送SQL （推荐）
            CmMerchantMapper mapper = session.getMapper(CmMerchantMapper.class); // Mapper 建议 方法作用域，一般在session作用域内
            List<CmMerchant> cmMerchants = null;
//            cmMerchants = mapper.selectByMerchantName("bbb");
            CmMerchant merchant = new CmMerchant();
//            merchant.setMerchantNo("Z0800458899002");
//            cmMerchants = mapper.selectByNoOrName2(merchant);
            cmMerchants = mapper.selectByIds(Arrays.asList(1, 2, 3));
            System.out.println("merchant2:");
            cmMerchants.stream().forEach(System.out::println);
        }
    }
}
